//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _APPS_BUSH_CINTERPRETER_H_
#define _APPS_BUSH_CINTERPRETER_H_

#include <buola/buola.h>
#include <buola/io/curi.h>
#include <buola/tty/ccompletion.h>
#include <buola/python/types.h>
#include <buola/io/glob.h>
#include "parser/cpartialmatch.h"
#include "parser/cparser.h"
#include "parser/ctoken.h"
#include "cbuiltin.h"
#include <map>

namespace buola { namespace bush {

class CInterpreter
{
    enum EState
    {
        STATE_EMPTY,
        STATE_CONTINUE
    };
    
public:
    CInterpreter();
    
    void SetPrompt(const std::wstring &pPrompt);

    CParser &GetParser()        {   return mParser;     }
    
    std::wstring GetPrompt();
    std::string GetWindowTitle();
    const std::vector<int> &GetIndentLevels()   {   return mIndentLevels;   }
    
    void CancelLine();
    void FeedLine(std::wstring &pLine);

    int RunShell(const std::wstring &pString);
    std::string RunShellOut(const std::wstring &pString);
    
    void SourceFile(const io::CURI &pURL,const python::YObject &pGlobals,const python::YObject &pLocals);
    void SourceFileModule(const io::CURI &pURL,const std::string &pModule=std::string());
    void EvalString(const std::wstring &pString,const python::YObject &pGlobals,const python::YObject &pLocals);

    std::string EvalIdentifier(TTokenRange pExpression);
    std::string EvalExpression(TTokenRange pExpression);
    std::vector<std::string> EvalExpressionToList(TTokenRange pExpression);
    
    bool AddAlias(const std::string &pDecl);
    bool RemoveAlias(const std::string &pName);
    CAlias *GetAlias(const std::wstring &pCmd)
    {
        auto lI=mAliases.find(pCmd);
        if(lI==mAliases.end())
            return nullptr;
        return lI->second;
    }
    const std::map<std::wstring,CAlias*> &GetAliases()  {   return mAliases;    }

    void AddBuiltin(const std::string &pCommand,CBuiltin *pBuiltin);
    void RemoveBuiltin(const std::string &pCommand);
    CBuiltin *GetBuiltin(const std::string &pCommand);
    const std::map<std::string,CBuiltin*> &GetBuiltins()  {   return mBuiltins;    }
    
    void AddCompleter(const std::string &pCommand,const python::YCallable &pCallable);
    void RemoveCompleter(const std::string &pCommand);
    python::YCallable GetCompleter(const std::string &pCmd);
    
    bool Complete(const std::wstring &pLine,int pCursor,tty::CCompletion<std::wstring> &pComp);
    ///returns true if python shouldn't be considered (some expressions that are almost for sure a file even if they
    ///also could match a python expression, such as several file components)
    bool CompleteShell(CPartialMatch &pMatch,tty::CCompletion<std::wstring> &pComp);
    void CompletePython(CPartialMatch &pMatch,tty::CCompletion<std::wstring> &pComp);
    void CompleteFilenames(const std::string &pPrefix,const std::string &pPart,tty::CCompletion<std::wstring>::SGroup &pGroup,
                            io::EGlob pGlobFlags=io::GLOB_NONE);
    void CompleteFilenames(const std::string &pPrefix,const std::string &pPart,tty::CCompletion<std::wstring>::SGroup &pGroup,
                           const std::vector<std::string> &pExt,io::EGlob pGlobFlags=io::GLOB_NONE);
    void CompleteCommand(const std::string &pPart,tty::CCompletion<std::wstring>::SGroup &pGroup);

    int AddJob(PPipeline pJob);
    void RemoveJob(int pJobID);
    const std::vector<PPipeline> &GetJobs() {   return mJobs;   }
    void SetPendingJobReport()      {   mPendingJobReport=true; }
    void CheckJobs();
    void SetCurrentJob(int pJob)    {   mCurrentJob=pJob;   }
    int GetCurrentJob()             {   return mCurrentJob; }
    
    std::vector<io::CURI> &GetCDStack()  {   return mCDStack;    }
    
private:
    python::YObject RunParsedLine(const std::wstring &pParsedLine,const python::YObject &pGlobals,const python::YObject &pLocals,
                       ERunMode pRunMode,bool pIgnoreError=false);
    python::YObject RunParsedLineModule(const std::wstring &pParsedLine,const std::string &pModule,
                       ERunMode pRunMode,bool pIgnoreError=false);
    
    EState RunCode(const std::wstring &pLine,std::vector<int> &pIndentLevels,
                   const python::YObject &pGlobals,const python::YObject &pLocals,ERunMode pRunMode);
    EState RunCodeModule(const std::wstring &pLine,std::vector<int> &pIndentLevels,
                   const std::string &pModule,ERunMode pRunMode);
    
private:
    std::wstring mPrompt;

    std::wstring mAccumLine;
    EState mState;    
    std::wstring mLastPrompt;
    std::vector<io::CURI> mCDStack;
    std::vector<int> mIndentLevels;
    std::map<std::string,python::YCallable> mCompleters;
    std::map<std::string,CBuiltin*> mBuiltins;
    std::map<std::wstring,CAlias*> mAliases;
    std::map<std::string,io::CURI> mCompletersAvailable;
    bool mCompletersLoaded;

    CParser mParser;
    
    std::vector<PPipeline> mJobs;
    bool mPendingJobReport;
    int mCurrentJob;
};

extern CInterpreter *gInterpreter;

/*namespace bush*/ } /*namespace buola*/ }

#endif
